package ds.dsr.server.handler;

import com.alibaba.fastjson.JSON;
import ds.dsr.log.Logger;
import ds.dsr.server.enums.OpEnum;
import ds.dsr.server.model.Message;
import ds.dsr.server.model.ServiceInfo;
import ds.dsr.server.params.ServerContext;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;

import java.util.Map;

/**
 * @author sunchong
 * @date 2018/4/23
 */
public class MessageHandler implements ChannelInboundHandler {

    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        Logger.info(channel.remoteAddress().toString()+"开始注册");
    }

    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        Logger.info(channel.remoteAddress().toString()+"取消注册");
    }

    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        onlineChannel(channel);
        Logger.info(channel.remoteAddress().toString()+"活跃状态");
    }

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        offlineChannel(channel);
        Logger.info(channel.remoteAddress().toString()+"不活跃");
    }

    public void channelRead(ChannelHandlerContext ctx, Object o) throws Exception {
        Channel channel = ctx.channel();
        Message<String> msg = parseMsg(o);
        solveMsg(msg, channel);



    }

    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

    }

    public void userEventTriggered(ChannelHandlerContext ctx, Object o) throws Exception {

    }

    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {

    }

    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

    }

    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception {
        Channel channel = ctx.channel();
        Logger.error(channel.remoteAddress().toString()+"抛出异常");
        throwable.printStackTrace();
    }

    private void selectCmd(Message message, Channel channel){
        OpEnum opEnum = OpEnum.getById(message.getCmd());
        if(null == opEnum){
            return;
        }
        switch (opEnum){
            case OP_GET_SERVICE_TABLE:
                serviceTablePush();
            case OP_SERVICE_REGISTER:
                serviceRegister(message);
                serviceTablePush();
                break;
            case OP_PONG:
                break;
            default:
                return;
        }
    }

    private Message<String> parseMsg(Object o){
        if(o instanceof String){
            return JSON.parseObject((String)o, Message.class);
        }
        return null;
    }

    private void solveMsg(Message message, Channel channel){
        selectCmd(message, channel);
    }

    private void serviceTablePush(){
        Message<Map<String, ServiceInfo>> pushTableInfo = new Message<>();
        pushTableInfo.setCmd(OpEnum.OP_GET_SERVICE_TABLE.getId());
        pushTableInfo.setData(ServerContext.serviceInfoTable);
        String pushInfo = buildMsg(pushTableInfo);
        for(Channel channel: ServerContext.channelQuence){
            channel.writeAndFlush(pushInfo);
        }
    }

    private void serviceRegister(Message message){
        ServiceInfo serviceInfo = JSON.parseObject((String)message.getData(), ServiceInfo.class);
        if(null != ServerContext.serviceInfoTable.get(serviceInfo.getHost()+":"+serviceInfo.getPort()+"/"+serviceInfo.getServiceName())){
            ServerContext.serviceInfoTable.put(serviceInfo.getHost()+":"+serviceInfo.getPort()+"/"+serviceInfo.getServiceName(), serviceInfo);
        }
    }

    private void onlineChannel(Channel onlineChannel){
        ServerContext.channelQuence.add(onlineChannel);
        ServerContext.onlineNum.incrementAndGet();
    }

    private void offlineChannel(Channel channel){
        ServerContext.channelQuence.remove(channel);
        ServerContext.onlineNum.decrementAndGet();
    }

    private String buildMsg(Message message){
        return JSON.toJSONString(message+"\r\n");
    }
}
